(function(w, $) {
    'use strict';

    // register the main object
    w.SimpleBsDialog = function(options) {
        this.options = $.extend({}, {
            id: newGuid(),
            appendTo:'body',
            width: 500,
            maxWidth: '',
            autoWidth: false,
            height: 280,
            maxHeight: '',
            autoHeight: false,
            title: '',
            closable: true,
            spinner: false,
            fullScreen: false,
            maximize: false,
            minimize: false,
            draggable: false,
            spinnerIcon: '<span class="spinner-border text-primary" role="status"></span>',
            closeByBackdrop: 'static',
            closeByKeyboard: false,
            html: null,
            load: null,
            cssClass: '',
            buttons: [],
            tools:[],
            onShow: function(dialogRef){},
            onShown: function(dialogRef){},
            onHide: function(dialogRef){},
            onHidden: function(dialogRef){},
        }, options);

    };

    // private methods
    function newGuid()
    {
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
            var r = Math.random() * 16 | 0, v = (c == 'x' ? r : r & 0x03 | 0x08);

            return v.toString(16);
        });
    }

    function setWidth(e, init)
    {
        var width = 0;
        var maxWidth = 0;
        // parse width
        if (e.data.options.width.toString().indexOf('px') >= 0 || e.data.options.width.toString().indexOf('%') >= 0) {
            width = e.data.options.width;
        } else {
            width = parseInt(e.data.options.width) + 'px';
        }
        if (e.data.options.maxWidth.toString().indexOf('px') >= 0 || e.data.options.maxWidth.toString().indexOf('%') >= 0) {
            maxWidth = e.data.options.maxWidth;
        } else if(e.data.options.maxWidth){
            maxWidth = parseInt(e.data.options.maxWidth) + 'px';
        }
        
        var dlgcss= {};
        if(!e.data.options.fullScreen){
            if(e.data.options.autoWidth === true){
                dlgcss['min-width'] = width;
            }else{
                dlgcss['width'] = width;
            }
            if(maxWidth !== 0){
                dlgcss['max-width'] = maxWidth;
            }
            $('#' + e.data.options.id).children('.modal-dialog').css(dlgcss);
            
            // set width
            if(init === true || (e.data.options.autoWidth === true && e.data.options.width.toString().indexOf('%') >= 0)) {
            
            }
            var left = Math.ceil(($(e.data.options.appendTo).width() - $('#' + e.data.options.id).children('.modal-dialog').width())/2);
            $('#' + e.data.options.id).children('.modal-dialog').css({left: left});
        }
        
    }

    function setHeight(e, init)
    {
        var height = 0;
        var maxHeight = 0;
        // parse height
        if (e.data.options.height.toString().indexOf('px') >= 0 || e.data.options.height.toString().indexOf('%') >= 0) {
            height = e.data.options.height;
        } else {
            height = parseInt(e.data.options.height) + 'px';
        }
        if (e.data.options.maxHeight.toString().indexOf('px') >= 0 || e.data.options.maxHeight.toString().indexOf('%') >= 0) {
            maxHeight = e.data.options.maxHeight;
        } else if(e.data.options.maxHeight){
            maxHeight = parseInt(e.data.options.maxHeight) + 'px';
        }
        // set height
        var dlgcss= {};
        if(!e.data.options.fullScreen){
            if(e.data.options.autoHeight === true){
                dlgcss['min-height'] = height;
            }else{
                dlgcss['height'] = height;
            }
            if(maxHeight !== 0){
                dlgcss['max-height'] = maxHeight;
            }
            $('#' + e.data.options.id).children('.modal-dialog').css(dlgcss);
            
            if (init === true || (e.data.options.autoHeight === true && e.data.options.height.toString().indexOf('%') >= 0)) {
            
            }
            var top = Math.ceil(($(e.data.options.appendTo).height() - $('#' + e.data.options.id).children('.modal-dialog').height())/2);
            $('#' + e.data.options.id).children('.modal-dialog').css({top: top});
        }
    }

    function setSize(e)
    {
        setWidth(e, false);
        setHeight(e, false);
    }

    function validOptions()
    {
        return [
            'width',
            'autoWidth',
            'height',
            'autoHeight',
            'maxWidth',
            'maxHeight',
            'fullScreen',
            'maximize',
            'minimize',
            'title',
            'closable',
            'spinner',
            'spinnerIcon',
        ];
    }

    function parseCssClass(cssClass)
    {
        var cssClasses = cssClass.split(' ');

        if (cssClasses.length == 0) {
            return '';
        }

        return ' ' + cssClasses.join(' ');
    }
    function initDraggable(dialog){
        if(dialog.options.draggable){
            $('#' + dialog.options.id).children('.modal-dialog').draggable({
                distance: 5
               ,containment: "parent"
               ,start :function(event, ui ){
                   if($(this).hasClass('modal-full')){
                       return false;
                   }
               }
               ,stop :function(event, ui ){
               }
            });
        }
    }
    
    // public methods
    SimpleBsDialog.prototype.open = function()
    {
        // store this
        var dialog = this;
        
        var buttons = '<button type="button" class="h-close '+(dialog.options.closable?'':'d-none')+'" data-dismiss="modal"><i class="fa fa-close" aria-hidden="true"></i></button>';
        var classes = parseCssClass(dialog.options.fullScreen?"modal-full":'') 
           + parseCssClass(dialog.options.cssClass);
        // bootstrap dialog
        $(dialog.options.appendTo).append('<div class="simple-bs-dialog modal fade' + '" id="' + dialog.options.id + '" tabindex="-1"><div class="modal-dialog'+classes+'"><div class="modal-content"><div class="modal-header"><h5 class="modal-title">' + dialog.options.title + '</h5><div class="tools-class">'+buttons+'</div></div><div class="modal-html"><div class="modal-body"></div><div class="modal-spinner' + (dialog.options.spinner ? '' : ' d-none') + '">' + dialog.options.spinnerIcon + '</div></div>' + (dialog.options.buttons.length > 0 ? '<div class="modal-footer"></div>' : '') + '</div></div></div>');
        
        if(dialog.options.html && "object" === $.type(dialog.options.html)){
            $('#' + dialog.options.id).find('.modal-body').append(dialog.options.html.children().clone());
        }else if(dialog.options.html && "string" === $.type(dialog.options.html)){
            $('#' + dialog.options.id).find('.modal-body').html(dialog.options.html);
        }else if(dialog.options.load && "string" === $.type(dialog.options.load)){
            $('#' + dialog.options.id).find('.modal-body').load(dialog.options.load);
        }
        
        // add buttons
        $.each(dialog.options.buttons, function(index, options) {
            var opts = $.extend({}, {
                id: newGuid(),
                label: '',
                cssClass: '',
                action: function(dialogRef){},
            }, options);

            var button = $('<button type="button" class="btn btn-default' + (opts.cssClass.length > 0 ? ' ' : '') + opts.cssClass + '" id="' + opts.id + '">' + opts.label + '</button>');
            button.on('click', function(e) {
                opts.action(dialog);
            });

            $('#' + dialog.options.id).find('.modal-footer').append(button);
        });
        // add tool-buttons
        var tools = [];
        if(dialog.options.maximize){
            tools.push({
                id: newGuid(),
                tips:'maximize',
                label: '<i class="fa fa-window-maximize" aria-hidden="true"></i>',
                cssClass: 'h-maximize',
                action: function(dialogRef){
                    var dlg = $('#' + dialog.options.id).children('.modal-dialog');
                    if(dlg.hasClass('modal-mini')){
                      dlg.removeClass('modal-mini');
                      dlg.addClass('modal-full');
                    }else if(!dialog.options.fullScreen){
                        dlg.toggleClass('modal-full');
                    }
                    if(!dlg.hasClass('modal-full')){
                        $(window).resize();
                    }else{
                        dlg.css({left:"",top:""});
                    }
                },
            });
        }
        if(dialog.options.minimize){
            tools.push({
                id: newGuid(),
                tips:'minimize',
                label: '<i class="fa fa-window-minimize" aria-hidden="true"></i>',
                cssClass: 'h-minimize ',
                action: function(dialogRef){
                    var dlg = $('#' + dialog.options.id).children('.modal-dialog');
                    if(dlg.hasClass('modal-full')){
                        dlg.removeClass('modal-full');
                    }else if(dialog.options.fullScreen){
                        dlg.addClass('modal-full');
                    }
                    dlg.toggleClass('modal-mini');
                    if(!dlg.hasClass('modal-mini')){
                        $(window).resize();
                    }else{
                        dlg.css({left:"",top:""});
                    }
                },
            });
        }
        if(dialog.options.tools){
            tools = $.extend(true,tools,dialog.options.tools);
        }
        $.each(tools, function(index, options) {
            var opts = $.extend({}, {
                id: newGuid(),
                label: '',
                tips:'',
                cssClass: '',
                action: function(dialogRef){},
            }, options);

            var button = $('<button type="button" title="'+ opts.tips +'" class="' + parseCssClass(opts.cssClass) + '" id="' + opts.id + '">' + opts.label + '</button>');
            button.on('click', function(e) {
                opts.action(dialog);
            });
            $('#' + dialog.options.id).find('.modal-header>.tools-class').prepend(button);
        });

        // destroy dom element
        $('#' + dialog.options.id).on('show.bs.modal', function() {
            // initial width
            setWidth({
                data: dialog,
            }, true);

            // initial height
            setHeight({
                data: dialog,
            }, true);

            // set dialog's auto size
            $(window).on('resize', dialog, setSize);

            // onShow event
            dialog.options.onShow(dialog);
        }).on('shown.bs.modal', function() {
            // onShown event
            dialog.options.onShown(dialog);
            
            initDraggable(dialog);
        }).on('hide.bs.modal', function(e) {
            // onHide event
            dialog.options.onHide(dialog);
        }).on('hidden.bs.modal', function(e) {
            // cancel dialog's auto size
            $(window).off('resize', setSize);

            // remove dialog's div
            $('#' + dialog.options.id).remove();

            // onHidden event
            dialog.options.onHidden(dialog);
        }).modal({
            'backdrop': dialog.options.closeByBackdrop,
            'keyboard': dialog.options.closeByKeyboard,
        });

        // return main object
        return this;
    }

    SimpleBsDialog.prototype.close = function()
    {
        $('#' + this.options.id).modal('hide');

        // return main object
        return this;
    }

    SimpleBsDialog.prototype.get = function(option)
    {
        if (validOptions().indexOf(option) > -1) {
            return this.options[option];
        }
    }

    SimpleBsDialog.prototype.set = function(options, value)
    {
        if (!$.isPlainObject(options) && validOptions().indexOf(options) > -1) {
            var option = options;

            options = {};
            options[option] = value;
        }

        if ($.isPlainObject(options)) {
            // store this
            var dialog = this;

            $.each(options, function(option, value) {
                switch (option) {
                case 'width': {
                    // new width
                    dialog.options.width = value;

                    // init new size
                    setWidth({
                        data: dialog,
                    }, true);

                    break;
                }
                case 'autoWidth': {
                    // new autoWidth
                    dialog.options.autoWidth = value;

                    // init new size
                    setWidth({
                        data: dialog,
                    }, true);

                    break;
                }
                case 'height': {
                    // new height
                    dialog.options.height = value;

                    // init new size
                    setHeight({
                        data: dialog,
                    }, true);

                    break;
                }
                case 'autoHeight': {
                    // new autoHeight
                    dialog.options.autoHeight = value;

                    // init new size
                    setHeight({
                        data: dialog,
                    }, true);

                    break;
                }
                case 'maxWidth': {
                    // new autoHeight
                    dialog.options.maxWidth = value;

                    // init new size
                    setWidth({
                        data: dialog,
                    }, true);

                    break;
                }
                case 'maxHeight': {
                    // new autoHeight
                    dialog.options.maxHeight = value;

                    // init new size
                    setHeight({
                        data: dialog,
                    }, true);

                    break;
                }
                case 'title': {
                    // update dialog's title
                    $('#' + dialog.options.id).find('.modal-title').html(dialog.options.title = value);

                    break;
                }
                case 'closable': {
                    // update dialog's closable
                    if (dialog.options.closable = value) {
                        $('#' + dialog.options.id).find('.modal-header button.close').removeClass('d-none');
                    } else {
                        $('#' + dialog.options.id).find('.modal-header button.close').addClass('d-none');
                    }

                    break;
                }
                case 'maximize': {
                    // update dialog's maximize
                    if (dialog.options.maximize = value) {
                        $('#' + dialog.options.id).find('.modal-header button.maximize').removeClass('d-none');
                    } else {
                        $('#' + dialog.options.id).find('.modal-header button.maximize').addClass('d-none');
                    }

                    break;
                }
                case 'minimize': {
                    // update dialog's minimize
                    if (dialog.options.minimize = value) {
                        $('#' + dialog.options.id).find('.modal-header button.minimize').removeClass('d-none');
                    } else {
                        $('#' + dialog.options.id).find('.modal-header button.minimize').addClass('d-none');
                    }

                    break;
                }
                case 'spinner': {
                    // update dialog's spinner
                    if (dialog.options.spinner = value) {
                        $('#' + dialog.options.id).find('.modal-spinner').removeClass('d-none');
                    } else {
                        $('#' + dialog.options.id).find('.modal-spinner').addClass('d-none');
                    }

                    break;
                }
                case 'spinnerIcon': {
                    // update dialog's spinnerIcon
                    $('#' + dialog.options.id).find('.modal-spinner').html(dialog.options.spinnerIcon = value);

                    break;
                }
                }
            });
        }

        // return main object
        return this;
    }
    
    SimpleBsDialog.prototype.getModalBody = function()
    {
        // get modal body
        return $('#' + this.options.id).find('.modal-body');
    }

    SimpleBsDialog.prototype.getButton = function(id)
    {
        // get button's object
        return $('#' + this.options.id).find('.modal-footer button#' + id);
    }

    SimpleBsDialog.prototype.getButtons = function()
    {
        // get all the buttons' object
        return $('#' + this.options.id).find('.modal-footer button');
    }

    // for lazy people
    SimpleBsDialog.show = function(options)
    {
        return (new SimpleBsDialog(options)).open();
    }

    // current version
    SimpleBsDialog.version = '2.0.0';
}(window, jQuery));